package org.gitman.agentplatform.model;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

import org.gitman.agentplatform.agent.api.AgentInfo;
import org.gitman.agentplatform.agent.api.InternalAgentInfo;

public class Graph {
	private Map<Integer, Vertex> id2vertex;
		
	public Graph(){
		id2vertex = new HashMap<Integer, Vertex>();
	}
	public Collection<Vertex> getVertices() {
		return id2vertex.values();
	}
	public void setVertices(Collection<Vertex> vertices) {
		id2vertex = new HashMap<Integer, Vertex>();
		for(Vertex v: vertices){
			id2vertex.put(v.getId(), v);
		}
	}
	public Collection<AgentInfo> getAgentsInRange(InternalAgentInfo agentInfo, Collection<InternalAgentInfo> agentsInfo, Integer observDistance) {
		Collection<AgentInfo> agentsInRange = new LinkedList<AgentInfo>();
		Set<Integer> idSet = getIdInRange(agentInfo.getCurrentVertexID(), observDistance);
		for(InternalAgentInfo info : agentsInfo){
			if(idSet.contains(info.getCurrentVertexID())){
				agentsInRange.add(info);
			}
		}
		return agentsInRange;
	}	
	private Set<Integer> getIdInRange(Integer sourceID, Integer observDistance) {
		Set<Integer> set = new HashSet<Integer>();
		Set<Vertex> curr = new HashSet<Vertex>();
		Set<Vertex> next = new HashSet<Vertex>();
		for(Vertex v : getVertices()){
			v.setVisited(false);
		}
		Vertex source = getVertexByID(sourceID);
		next.add(source);
		source.setVisited(true);
		while(!next.isEmpty() && observDistance-- >= 0){
			curr = next;
			next = new HashSet<Vertex>();
			for(Vertex v : curr){
				set.add(v.getId());
				for(Vertex n : v.getNormalAndInverseNeighbours()){
					if(!n.wasVisited()){
						n.setVisited(true);
						next.add(n);
					}
				}
			}
		}
		return set;
	}
	public Vertex getVertexByID(Integer id){
		return id2vertex.get(id);
	}
	public void addVertex(Vertex vertex){
		id2vertex.put(vertex.getId(), vertex);
	}
	public void removeVertex(Vertex vertex){
		id2vertex.remove(vertex.getId());
	}
	public boolean canMove(Integer currentVertexID, Integer moveID) {
		Vertex v = getVertexByID(currentVertexID);
		Vertex m = getVertexByID(moveID);
		return v.isNeighbour(m);
	}
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder("Graph:\n");
		for(Vertex v : getVertices()){
			builder.append(v.toString());
		}
		return builder.toString();
	}
}
